package com.share.example.bcs.server.server;

import com.share.example.bcs.server.server.protocol.ProtocolDispatcher;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Data
@Slf4j
@Component
public class NettyServer {
    //端口
    private int port = 12345;
    // accept线程组，用来接受连接
    private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    // I/O线程组， 用于处理业务逻辑
    private final EventLoopGroup workerGroup = new NioEventLoopGroup(1);

    @PostConstruct
    public void init() {
        log.info("start server ...");

        // Server 服务启动
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup);// 绑定两个线程组
        bootstrap.channel(NioServerSocketChannel.class); // 指定通道类型
        bootstrap.option(ChannelOption.SO_BACKLOG, 100); // 设置TCP连接的缓冲区

        try {
            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast(new ProtocolDispatcher());//只添加一个分发器
                }
            });

            // 可选参数
            bootstrap.childOption(ChannelOption.TCP_NODELAY, true);

            // 通过bind启动服务
            log.info("start server at port={}", port);
            ChannelFuture future = bootstrap.bind(port).sync();
            future.addListener(f -> {
                if (f.isSuccess()) {
                    log.info("服务启动成功");
                } else {
                    log.info("服务启动失败");
                }
            });

            // 阻塞主线程，知道网络服务被关闭
            future.channel().closeFuture().sync();

        } catch (Exception e) {
            log.error("Server fail");
            throw new RuntimeException(e);
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

}
